home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 2,801 to 2,900
/
aol-file-protocol-4400-2801-to-2900.zip
/
AOLDLs
/
C++ Files Library
/
CustomNew.cp
/
CustomNew.cp
next >
Wrap
Text File
|
2014-09-28
|
8KB
|
224 lines
// CustomNew.p by Franìois Pottier (pottier@clipper.ens.fr)
// December 1st, 1994
// --- WHAT IT IS - HOW TO USE IT ---------------------------------------------------------------------------------------
// This file redefines the standard new and delete operators.
// Advantages over MetroWerks's definition:
// 1. Memory is taken from the application heap or the temporary heap (preferrably the first) for greater flexibility.
// 2. Unused memory pools are released to the system.
// 3. Less fragmentation, because the MetroWerks delete operator doesn't always join adjacent free blocks.
// 4. If pool allocation fails, new doesn't revert to calling NewPtr for each block. It's a good thing, because otherwise the program
// would just slow down to a crawl (NewPtr is much slower than new) and die a horrible death, should the Toolbox run out of space.
// Finally, I keep a count of used blocks and free blocks, which can help assess the program's memory usage and fragmentation.
// How to use:
// - Add CustomNew.cp to your project.
// --- LEGAL TERMS -----------------------------------------------------------------------------------------------------
// Although I wrote these routines entirely myself, they are loosely based on MetroWerks code.
// As far as I am concerned, you can use them freely in any of your programs. My only request is that you notify me if you find
// bugs or devise improvements. My email address is pottier@clipper.ens.fr
// Remember, this code has NOT been THOROUGHLY TESTED!
// --- OK FOLKS, LET'S HAVE THE CODE ------------------------------------------------------------------------------------
#include <stddef.h>
enum {
kPoolSize = 65536L, // Memory is allocated in 64K chunks
kBigSize = 2048L // Any allocations bigger than 2K go through the OS directly
};
typedef struct FreeMemList { // Free blocks are linked together in a list
struct FreeMemList *next; // Pointer to next free block
long size; // Size of this block
} FreeMemList;
typedef struct MemPool { // Memory is allocated from pools (locked handles)
struct MemPool *next; // Pointer to next pool
FreeMemList *freeHead; // Start of free blocks list
long usedBlocks, freeBlocks; // Statistics
Byte data[]; // Blocks
} MemPool;
MemPool* gPoolHead = NULL; // List of pools
long BytesTakenFromTempZone (void);
static Handle MakeLockedHandle (long size) // Create a locked handle from the application heap
{ // or the temporary zone
Handle h;
OSErr e;
h = NewHandle(size);
if (h == NULL) {
h = TempNewHandle(size, &e);
if ( h ) HLock(h);
}
else
HLockHi(h);
return h;
}
static Boolean NewPool (void) // Add a new pool to the pool list
{
Handle h;
MemPool* pool;
h = MakeLockedHandle(kPoolSize);
if (h == NULL)
return false;
pool = (MemPool*) *h;
pool->next = gPoolHead;
pool->freeHead = (FreeMemList*) pool->data;
pool->freeHead->next = NULL;
pool->freeHead->size = (Ptr) pool + kPoolSize - (Ptr) pool->data;
pool->usedBlocks = 0;
pool->freeBlocks = 1;
gPoolHead = pool;
return true;
}
static void* AllocFromPool (MemPool* pool, long size)
{
FreeMemList *block; // The block under consideration
FreeMemList* *link; // The place which points to block in the free blocks list
Ptr result;
for (link = &pool->freeHead; (block = *link) != nil; link = &block->next) // Walk the free blocks list
if (size <= block->size) { // If a free block is big enough
if (block->size >= size + sizeof(FreeMemList)) { // If it's really big enough, we can split it
block->size -= size; // The low part remains a free block
result = (Ptr) block + block->size; // The high part becomes allocated
}
else { // If it's just big enough, we can't split it
*link = block->next; // So we remove it from the free blocks list
result = (Ptr) block; // And we mark it all as allocated
pool->freeBlocks--;
}
pool->usedBlocks++;
* (long*) result = size; // The first four bytes contain the new block's size
return (result + 4);
}
return NULL;
}
// We assume the free blocks list to be always ordered from bottom to top, and it is because we insert new free blocks in the right
// place. This allows us to easily join adjacent free blocks into a single one when deleting a block, thus reducing stupid fragmentation.
static void DeleteFromPool (MemPool* pool, Ptr pointer, long size)
{
FreeMemList *block, *previous, *next;
FreeMemList* *link;
previous = next = NULL; // Look for any adjacent free blocks
for (link = &pool->freeHead; (block = *link) != nil; link = &block->next) // Walk the free blocks list
if (pointer == (Ptr) block + block->size) // We have found a free block just before ours
previous = block;
else if (pointer + size == (Ptr) block) { // We have found a free block just after ours
next = block;
goto Coalesce; // Stop searching now, there's nothing more up there and we will need the value of link
}
else if (pointer + size < (Ptr) block) // We have found no adjacent block
goto Coalesce; // The current value of link tells us where to insert the new free block
Coalesce:
pool->usedBlocks--;
if (previous != NULL && next != NULL) { // We now have 3 free blocks, join them
previous->size += size + next->size;
previous->next = next->next;
pool->freeBlocks--;
}
else if (previous) // Expand the free block below
previous->size += size;
else if (next) { // Expand the free block above
((FreeMemList*) pointer)->next = next->next;
((FreeMemList*) pointer)->size = next->size + size;
*link = (FreeMemList*) pointer;
}
else { // Add a free block to the list
((FreeMemList*) pointer)->next = *link;
((FreeMemList*) pointer)->size = size;
*link = (FreeMemList*) pointer;
pool->freeBlocks++;
}
}
void *operator new (size_t size)
{
MemPool* pool;
void* result;
size = (size & 0xFFFFFFFC) + 8; // Make sure size is a multiple of 4, and add 4 bytes to store the block size
if (size >= kBigSize) { // If the requested size is big
Handle h = MakeLockedHandle(size); // Use the Memory Manager directly
if (h == NULL)
return NULL;
* (long*) *h = -1L; // This special value serves to recognize standalone blocks
return (*h + 4);
}
pool = gPoolHead; // Try to find a pool with enough room
while (pool) {
if ( (result = AllocFromPool(pool, size)) != nil )
return result;
pool = pool->next;
}
if (NewPool()) // If no pool has enough space, create a new pool
return AllocFromPool(gPoolHead, size);
return NULL; // If we can't create a new pool, fail - *don't* revert to NewPtr, it's too damn slow and would hopelessly fill up the heap
}
void operator delete (void *pointer)
{
long size;
MemPool* pool;
MemPool* *link;
if (pointer) {
pointer = (Ptr) pointer - 4; // Retrieve the block size, which is stored 4 bytes below
size = * (long*) pointer;
if (size == -1L) // If the size tag is -1, the block is a handle
DisposeHandle(RecoverHandle((Ptr) pointer));
else {
link = &gPoolHead; // Find which pools the block belongs to
while ((pool = *link) != nil && ((Ptr) pointer < (Ptr) pool || (Ptr) pointer > (Ptr) pool + kPoolSize))
link = &pool->next;
DeleteFromPool(pool, (Ptr) pointer, size); // Delete the block from this pool
if (pool->usedBlocks == 0) { // If this pool isn't used any more
*link = pool->next; // Remove it from the pool queue
DisposeHandle(RecoverHandle((Ptr) pool)); // And release it
}
}
}
}
long BytesTakenFromTempZone (void) // For informational purposes, returns the number of
{ // bytes taken from the Multifinder zone. Note that this
MemPool* pool; // figure takes only pools into accounts, not stand-alone
Handle h; // blocks.
long size;
size = 0;
for (pool = gPoolHead; pool; pool = pool->next) {
h = RecoverHandle((Ptr) pool);
if (HandleZone(h) != ApplicZone())
size += GetHandleSize(h);
}
return size;
}
// THAT'S ALL FOLKS. HOPE YOU ENJOYED THE SHOW -----------------------------------------------------------------------